home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Linux Cubed Series 7: Sunsite
/
Linux Cubed Series 7 - Sunsite Vol 1.iso
/
system
/
news
/
readers
/
skim-0.8
/
skim-0
/
skim-0.8.4
/
StandardIO.c
< prev
next >
Wrap
C/C++ Source or Header
|
1996-02-18
|
11KB
|
507 lines
/*
* NAME
* StandardIO.c
* DESCRIPTION
* The class StandardIO is an adapter for the standard I/O of ANSI C (class
* FILE). StandardIO adds implicit error handling and support for variable
* length buffers (VarBuf). If a StandardIO operation returns, it was
* successful.
* COPYRIGHT
* Skim - Off-line news reading package optimized for slow lines.
* Copyright (C) 1996 Rene W.J. Pijlman
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
* VERSION
* Skim version 0.8.4.
*/
#include <stdio.h>
#include <errno.h>
#include <assert.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdlib.h>
#include "MemAlloc.h"
#include "VarBuf.h"
#include "StandardIO.h"
#define CLASS_NAME "StandardIO"
#include "CheckForDebris.h"
struct _StandardIO {
VarBuf FileName;
FILE * File;
Boolean OpenForRead;
Boolean OpenForWrite;
};
#ifndef NDEBUG
static Boolean ClassInvariant( StandardIO This )
{
assert( This != NULL );
if ( This->File == NULL )
{
assert( This->FileName == NULL );
assert( !This->OpenForRead );
assert( !This->OpenForWrite );
}
else
{
assert( This->FileName != NULL );
assert( This->OpenForRead || This->OpenForWrite );
}
return This != NULL &&
((This->File == NULL) == (This->FileName == NULL)) &&
(This->File == NULL || This->OpenForRead || This->OpenForWrite) &&
(This->File != NULL || (!This->OpenForRead && !This->OpenForWrite));
}
#endif
struct _StandardIO _StandardInput;
struct _StandardIO _StandardOutput;
struct _StandardIO _StandardError;
StandardIO StandardInput = &_StandardInput;
StandardIO StandardOutput = &_StandardOutput;
StandardIO StandardError = &_StandardError;
static Boolean ClassInitialized = False;
static void ClassDestruct( int ExitStatus, void * ClientData )
{
SIODestroy( StandardInput );
StandardInput = NULL;
SIODestroy( StandardOutput );
StandardOutput = NULL;
SIODestroy( StandardError );
StandardError = NULL;
}
static void InitializeClass( void )
{
VarBuf StandardInputFileName = VBCreate();
VarBuf StandardOutputFileName = VBCreate();
VarBuf StandardErrorFileName = VBCreate();
VBAppendString( StandardInputFileName, "<standard input>" );
VBAppendString( StandardOutputFileName, "<standard output>" );
VBAppendString( StandardErrorFileName, "<standard error>" );
StandardInput->File = stdin;
StandardInput->FileName = StandardInputFileName;
StandardInput->OpenForRead = True;
StandardInput->OpenForWrite = False;
StandardOutput->File = stdout;
StandardOutput->FileName = StandardOutputFileName;
StandardOutput->OpenForRead = False;
StandardOutput->OpenForWrite = True;
StandardError->File = stderr;
StandardError->FileName = StandardErrorFileName;
StandardError->OpenForRead = False;
StandardError->OpenForWrite = True;
if ( on_exit( ClassDestruct, NULL ) != 0 )
{
fprintf( stderr, "Cannot register function with on_exit()\n" );
exit( EXIT_FAILURE );
}
ClassInitialized = True;
}
/*
* Must be used in all non-static functions, since operations can be
* performed on the globals StandardInput, StandardOutput, StandardError
* without a call to SIOCreate().
*/
#define INITIALIZE_CLASS { if ( !ClassInitialized ) InitializeClass(); }
StandardIO SIOCreate( void )
{
StandardIO New;
INITIALIZE_CLASS;
New = MemAlloc( sizeof(struct _StandardIO) );
New->FileName = NULL;
New->File = NULL;
New->OpenForRead = False;
New->OpenForWrite = False;
assert( ClassInvariant( New ) );
IncrementObjectCount();
return New;
}
void SIODestroy( StandardIO This )
{
INITIALIZE_CLASS;
if ( This != NULL )
{
assert( ClassInvariant(This) );
SIOFileClose( This );
if ( This != StandardInput &&
This != StandardOutput &&
This != StandardError )
{
MemFree(This);
DecrementObjectCount();
}
}
}
Boolean SIOFileExists( const char * FileName )
{
struct stat stat_buf;
INITIALIZE_CLASS;
return stat( FileName, &stat_buf ) == 0;
}
void SIORemove( const char * FileName )
{
assert( SIOFileExists( FileName ) );
if ( remove(FileName) != 0 )
{
fprintf( stderr, "Cannot remove " );
perror( FileName );
exit( EXIT_FAILURE );
}
assert( !SIOFileExists( FileName ) );
}
static void SIOFileOpen_(
StandardIO This,
const char * FileName,
OpenMode Mode,
Boolean OpenFile,
int FileDescriptor )
{
const char * ModeString = NULL;
assert( ClassInvariant(This) );
assert( !This->OpenForRead && !This->OpenForWrite );
assert( FileName != NULL && strlen(FileName) > 0 );
assert( Mode != OpenModeWrite || !SIOFileExists(FileName) );
switch ( Mode )
{
case OpenModeRead:
case OpenModeReadIgnore:
ModeString = "r";
This->OpenForRead = True;
break;
case OpenModeWrite:
case OpenModeWriteDiscardOld:
ModeString = "w";
This->OpenForWrite = True;
break;
case OpenModeAppend:
ModeString = "a";
This->OpenForWrite = True;
break;
case OpenModeReadAndWriteDiscardOld:
ModeString = "r+";
This->OpenForRead = True;
This->OpenForWrite = True;
break;
default:
assert( False );
break;
}
This->File = OpenFile ? fopen( FileName, ModeString ) :
fdopen( FileDescriptor, ModeString );
if ( This->File != NULL )
{
assert( This->FileName == NULL );
This->FileName = VBCreate();
VBAppendString( This->FileName, FileName );
}
else if ( Mode == OpenModeReadIgnore && errno == ENOENT )
{
This->OpenForRead = False;
This->OpenForWrite = False;
}
else
{
fprintf( stderr, "Cannot open " );
perror( FileName );
exit( EXIT_FAILURE );
}
assert( ClassInvariant(This) );
assert( ( Mode == OpenModeReadIgnore && errno == ENOENT ) ||
This->OpenForRead || This->OpenForWrite );
}
void SIOFileOpen(
StandardIO This,
const char * FileName,
OpenMode Mode )
{
INITIALIZE_CLASS;
assert( ClassInvariant(This) );
SIOFileOpen_( This, FileName, Mode, True, 0 );
}
void SIOFileOpenFileDescriptorVB(
StandardIO This,
int FileDescriptor,
VarBuf PseudoFileName,
OpenMode Mode )
{
INITIALIZE_CLASS;
assert( ClassInvariant(This) );
SIOFileOpen_(This, VBAsString(PseudoFileName), Mode, False, FileDescriptor);
}
void SIOFileOpenVB(
StandardIO This,
VarBuf FileName,
OpenMode Mode )
{
INITIALIZE_CLASS;
assert( ClassInvariant(This) );
SIOFileOpen( This, VBAsString(FileName), Mode );
}
void SIOFileClose( StandardIO This )
{
INITIALIZE_CLASS;
assert( ClassInvariant(This) );
if ( This->File != NULL )
{
if ( This != StandardInput &&
This != StandardOutput &&
This != StandardError )
{
if ( fclose(This->File) == EOF )
{
fprintf( stderr, "Cannot close " );
perror( VBAsString(This->FileName) );
exit( EXIT_FAILURE );
}
}
This->File = NULL;
VBDestroy( This->FileName );
This->FileName = NULL;
This->OpenForRead = False;
This->OpenForWrite = False;
}
assert( ClassInvariant(This) );
assert( !This->OpenForRead && !This->OpenForWrite );
}
Boolean SIOIsOpenForWrite( StandardIO This )
{
INITIALIZE_CLASS;
assert( ClassInvariant(This) );
return This->OpenForWrite;
}
Boolean SIOIsOpenForRead( StandardIO This )
{
INITIALIZE_CLASS;
assert( ClassInvariant(This) );
return This->OpenForRead;
}
void SIOPrintf( StandardIO This, const char * FormatString, ... )
{
VarBuf Buffer = VBCreate();
va_list ArgumentPointer;
INITIALIZE_CLASS;
assert( ClassInvariant(This) );
assert( This->OpenForWrite );
va_start( ArgumentPointer, FormatString );
VBPrintfVA( Buffer, FormatString, ArgumentPointer );
if ( fprintf( This->File, "%s", VBAsString( Buffer ) ) == EOF )
{
fprintf( stderr, "Cannot write to " );
perror( VBAsString(This->FileName) );
exit( EXIT_FAILURE );
}
va_end( ArgumenPointer );
VBDestroy( Buffer );
}
Boolean SIOEndOfFile( StandardIO This )
{
INITIALIZE_CLASS;
assert( ClassInvariant(This) );
assert( This->OpenForRead );
return feof( This->File );
}
void SIOFileGetPartOfLine( StandardIO This, char * Buffer, int Size )
{
INITIALIZE_CLASS;
assert( ClassInvariant(This) );
assert( This->OpenForRead );
if ( fgets( Buffer, Size, This->File ) == NULL )
{
/* NULL from fgets() means EOF or error. */
if ( ferror( This->File ) )
{
fprintf( stderr, "Cannot read from " );
perror( VBAsString(This->FileName) );
exit(EXIT_FAILURE);
}
}
}
void SIOPrintError( const char * Prefix )
{
INITIALIZE_CLASS;
assert( ClassInvariant(StandardError) );
assert( StandardError->OpenForWrite );
perror( Prefix );
}
void SIOFlushBuffers( StandardIO This )
{
INITIALIZE_CLASS;
assert( ClassInvariant(This) );
assert( This->OpenForWrite );
if ( fflush( This->File ) == EOF )
{
fprintf( stderr, "Cannot write to " );
perror( VBAsString(This->FileName) );
exit( EXIT_FAILURE );
}
}
void SIOInternetCommand( StandardIO This, const char * Command )
{
INITIALIZE_CLASS;
assert( ClassInvariant(This) );
assert( This->OpenForWrite );
SIOPrintf( This, "%s\r\n", Command );
SIOFlushBuffers( This );
}
int SIOFileDescriptor( StandardIO This )
{
INITIALIZE_CLASS;
assert( ClassInvariant(This) );
assert( This->File != NULL );
return( fileno(This->File) );
}
int SIORead( StandardIO This, void * Buffer, int BufferSize )
{
size_t BytesRead;
INITIALIZE_CLASS;
assert( ClassInvariant(This) );
assert( This != NULL );
assert( SIOIsOpenForRead(This) );
BytesRead = fread( Buffer, (size_t)1, (size_t)BufferSize, This->File );
if ( BytesRead < 0 )
{
fprintf( stderr, "Error reading from " );
perror( VBAsString(This->FileName) );
exit(EXIT_FAILURE);
}
return BytesRead;
}
void SIOWrite( StandardIO This, void * Buffer, int BufferSize )
{
int BytesWritten;;
INITIALIZE_CLASS;
assert( ClassInvariant(This) );
BytesWritten = fwrite( Buffer, (size_t)1, (size_t)BufferSize, This->File );
if ( BytesWritten != BufferSize )
{
fprintf( stderr, "Error writing to" );
perror( VBAsString(This->FileName) );
exit(EXIT_FAILURE);
}
}